/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

Cu.import("resource://savefileto/common.jsm");
Cu.import("resource://savefileto/savefileto.jsm");


const dialog =
{
    set result(value) { window.arguments[0].wrappedJSObject.result = value; },
    
    onLoad: function()
    {
        this._ = new StringBundle("chrome://savefileto/locale/variable.properties").getter;
        
        this.folderDialog = window.opener.dialog;
        
        let tree = document.getElementById("tree");
        let treeView = new TreeView(savefileto.folderVariables);
        tree.view = this.treeView = treeView;
        
        this._updateUi();
    },
    
    onTreeSelect: function()
    {
        this._updateUi();
    },
    
    onTreeDoubleClick: function(event)
    {
        if (event.button != 0)
            return;
        
        let row = {};
        this.treeView.treeBoxObject.getCellAt(event.clientX, event.clientY, row, {}, {});
        if (row.value == -1)
             return;
        
        document.documentElement.acceptDialog();
    },
    
    onDialogExtra1: function()
    {
        let self = this;
        let entry = this.treeView.selectedEntry;
        this.folderDialog.openFolderPicker(entry.value, function(value, filePicker)
        {
            if (value != Ci.nsIFilePicker.returnOK)
                return;
            
            if (self._setDialogResult(entry, filePicker.file))
                window.close();
            else
            {
                let title = self._("error.title");
                let message = self._("error.notSubFolder", filePicker.file.path, entry.name, entry.value.path);
                Services.prompt.alert(window, title, message);
            }
        });
    },
    
    onDialogAccept: function()
    {
        return this._setDialogResult(this.treeView.selectedEntry);
    },
    
    _setDialogResult: function(entry, file)
    {
        if (! entry)
            return false;
        
        if (! file)
            this.result = {file: entry.value, path: "$" + entry.name};
        else if (file.path.startsWith(entry.value.path))
            this.result = {file: file, path: "$" + file.path.replace(entry.value.path, entry.name)};
        else
            return false;
        
        return true;
    },
    
    _updateUi: function()
    {
        let selected = (this.treeView.selectedEntry != null);
        
        document.documentElement.getButton("accept").disabled = (! selected);
        document.documentElement.getButton("extra1").disabled = (! selected);
    },
}


function TreeView(model)
{
    this._model = [];
    this._view = [];
    this._sortColumn = null;
    
    this.model = model;
}

TreeView.prototype =
{
    QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView]),
    
    get model() { return this._model; },
    get view()  { return this._view; },
    
    set model(model)
    {
        if (model != this._model)
            this._preserveSelection(function() { this._update(model); });
    },
    
    get selectedIndex()
    {
        // on a single selection tree, currentIndex is currently selected index only if selection count is 1
        return ((this.selection.count == 1) ? this.selection.currentIndex : -1);
    },
    
    get selectedEntry()
    {
        let index = this.selectedIndex;
        return ((index != -1) ? this._view[index] : null);
    },
    
    _preserveSelection: function(func)
    {
        let selectedEntry = null;
        
        if (this.treeBoxObject)
        {
            selectedEntry = this.selectedEntry;
            this.selection.selectEventsSuppressed = true;
        }
        
        func.call(this);
        
        if (this.treeBoxObject)
        {
            this.selection.select(this._view.indexOf(selectedEntry));
            this.selection.selectEventsSuppressed = false;
        }
    },
    
    _update: function(model)
    {
        this._model = model;
        this._view = model.slice();
        this._doSort();
    },
    
    _doSort: function(compare)
    {
        compare = compare || this._getCompare(this._sortColumn);
        if (! compare)
            return;
        
        if (this._sortColumn.element.getAttribute("sortDirection") != "descending")
            this._view.sort(compare);
        else
            this._view.sort(function(a, b) { return compare(b, a); });
    },
    
    _getCompare: function(col)
    {
        if (! col)
            return null;
        
        let self = this;
        
        switch (col.id)
        {
            case "tcol_name": return function(a, b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); };
            case "tcol_path": return function(a, b) { return a.value.path.toLowerCase().localeCompare(b.value.path.toLowerCase()); };
            default: return null;
        }
    },
    
    // nsITreeView
    
    get rowCount() { return this._view.length; },
    
    setTree: function(treeBoxObject)
    {
        this.treeBoxObject = treeBoxObject;
        
        if (! treeBoxObject)
            return;
        
        // init sortColumn
        this._sortColumn = null;
        for (let col = this.treeBoxObject.columns.getFirstColumn(); col; col = col.getNext())
        {
            let sortDirection = col.element.getAttribute("sortDirection");
            if ((sortDirection == "ascending") || (sortDirection == "descending"))
            {
                this._sortColumn = col;
                break;
            }
        }
    },
    
    getCellText: function(row, col)
    {
        switch (col.id)
        {
            case "tcol_name": return this._view[row].name;
            case "tcol_path": return this._view[row].value.path;
            default: return "";
        }
    },
    
    cycleHeader: function(col)
    {
        let compare = this._getCompare(col);
        if (! compare)
            return;
        
        let newSortDirection = ((col.element.getAttribute("sortDirection") != "ascending") ? "ascending" : "descending");
        
        // reset old sort column's sortDirection
        // set attribute (instead of remove) so that persist works
        if (this._sortColumn)
            this._sortColumn.element.setAttribute("sortDirection", "natural");
        
        this._sortColumn = col;
        this._sortColumn.element.setAttribute("sortDirection", newSortDirection);
        
        this._preserveSelection(function() { this._doSort(compare); });
        this.treeBoxObject.invalidate();
    },
    
    isSorted: function()
    {
        return (!! this._sortColumn);
    },
    
    isContainer: function(row) { return false; },
    isSeparator: function(row) { return false; },
    getLevel: function(row) { return 0; },
    getImageSrc: function(row, col) { return null; },
    getRowProperties: function(row) { return ""; },
    getCellProperties: function(row, col) { return ""; },
    getColumnProperties: function(colid, col) { return ""; },
}
